/*
Este programa es un analizador sintactico para la gramatica que posee el lenguaje de programacion c--
        Copyright © 2011  Martinelli, Fernán Gabriel (fmartinelli89@gmail.com)
                          Riberi, Franco Gaspar      (fgriberi@gmail.com)
                          Varea, Agustín	     (agvarea@gmail.com)

Todos los derechos reservados

Este programa es software libre: usted puede redistribuirlo y/o modificarlo conforme a los términos 
de la Licencia Pública General de GNU publicada por la Fundación para el Software Libre, ya sea la 
versión 3 de esta Licencia o (a su elección) cualquier versión posterior.

Este programa se distribuye con el deseo de que le resulte útil, pero SIN GARANTÍAS DE NINGÚN TIPO; 
ni siquiera con las garantías implícitas de COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO DETERMINADO.  
Para más información, consulte la Licencia Pública General de GNU.

Junto con este programa, se debería incluir una copia de la Licencia Pública General de GNU.
De no ser así, ingrese en <http://www.gnu.org/licenses/>.

*/

%{
#include <stdio.h>
#include <stdlib.h> /* Para usar el comando exit que permite cortar la ejecucion */
extern FILE *yyin;
extern int num_lineas;
%}

/* Declaración de los tokens definidos en el archivo lenguajeLex.l (flex) */
%token WHILE BREAK CONTINUE IF ELSE RETURN INT FLOAT  IGUALIGUAL AMPERAMPER  BARRABARRA  INTDENOTATION FLOATDENOTATION IDENTIFIER ERROR

/* Definición de mi simbolo inicial */
%start Program


/* Comienza la definición de la gramatica */

/* YYACCEPT corta la ejecucion de yyparse() haciendo que el mismo devuelva 0 */
/* para que no siga buscando cadenas siguientes y finalice la ejecución */

%%
 	
/* EXPRESIONES LOGICAS,MATEMATICAS Y RELACIONALES */
/* ESTRUCTURA DEL PROGRAMA */
Program : TypeSpecifier IDENTIFIER '(' declPar ')' Compound   			{ YYACCEPT; };
	
declPar : ParameterDecl ',' declPar | ParameterDecl ;

ParameterDecl : TypeSpecifier IDENTIFIER ;		

TypeSpecifier : INT | FLOAT ;

Compound : '{' cuerpo '}' ; 

cuerpo : var stat | ;

var : VariableDecl var | ;

stat : Statement stat | Statement;

VariableDecl : TypeSpecifier a ';' ;

a : IDENTIFIER b c ;

b : '=' Expression | ;		
 
c : ',' a| ;

Statement : Compound | Conditional | Iteration | w ';' ;

w : BREAK | CONTINUE | RETURN Expression | Computation | ;

Conditional : IF '(' Expression ')' Statement d ;

d : ELSE Statement | ;

Iteration : WHILE '(' Expression ')' Statement ;

Computation : Expression ;

Expression : IDENTIFIER '=' Expression 
	   | Condition 
	   ;

Condition : Disjunction
	  | Disjunction '?' Expression ':' Condition
	  ;

Disjunction : Conjunction
	    | Disjunction BARRABARRA Conjunction
	    ;

Conjunction : Comparison
	    | Conjunction AMPERAMPER Comparison
	    ;	

Comparison : Relation
	   | Relation IGUALIGUAL Relation
	   ;

Relation : Sum
	 | Sum '<' Sum
	 | Sum '>' Sum
	 ;

Sum : Term
    | Sum '+' Term
    | Sum '-' Term
    ;

Term : Factor
     | Term '*' Factor	
     | Term '/' Factor
     | Term '%' Factor
     ;

Factor : Primary
       | '!' Factor
       | '-' Factor
       ;

Primary : INTDENOTATION
	| FLOATDENOTATION 
	| IDENTIFIER
	| '(' Expression ')'
	;
%%

typedef char * string;
yywrap() 
{
	return 1;
}


/* Este metodo es llamado por yyparse si ocurre un error */
/* En caso de ocurra dicho error se ejecutara el cuerpo de este metodo*/
yyerror (char *a) 
{
  printf ("%s\n", a);
  printf ("%s", "ERROR EN LINEA: ");
  printf("%d\n",num_lineas ); 

}

/* Funcion que verifica si el nombre de un archivo es correcto. Es decir, solo tratamos archivos de extension .c-*/
int archivoValido(char* arch)  
{
   char*aux = arch;
   int f;
   int lenght =0;
   for (f=0; *arch != '\0'; f++) {
       lenght++;
      *arch++;
   }  
   int i = 0;	
   char c = aux[i];
   if (c != '.'){
      while (c != '.') {
         i++;
         c = aux[i]; 	
      }
      i++;
      c = aux[i];
      if (c == 'c') {
         i++;
         c = aux[i];
	 if (c == '-') {
	    i++;
	    c = aux[i];

	    if (i == lenght) {
		return 1;
   	    }else{
	       return 0;
	    }  
	 }else{
	    return 0;
	 }
      }else{
         return 0;
      }			     
   }else{
     return 0;
   }	 
}	

/* Si el archivo esta mal escrito, se posibilita volver a escribirlo, en caso de que no exista, se termina*/
int main(int argc, string argv[])
{
  string archivo;
  if (argc != 2) {
	printf("Mal uso. Uso corrector <./run.su archivo.c-> \n");
	exit(1);
  }  
  archivo = argv[1];
  if (archivoValido(archivo) == 0) {
  	printf("Archivo no  reconocido. Verifique su extension. \n");   
	exit(1);
  }else{
	yyin = fopen(archivo,"r");
  	if (yyin == NULL) {
        	printf("Archivo no existente. \n");
		exit(1);
 	}else{
		int c = yyparse(); 	  /* yyparse devuelve 0 en caso de finalizar el "parseo" con éxito */	  
		if(c == 0) {
			printf("COMPILACION EXITOSA\n");
			printf("Numero de lineas compiladas: ");
		        printf("%d\n",num_lineas );
		        printf("\n");
		}
		fclose(yyin);
		return 0;

	}
  } 
}
